from PyQt4.QtGui import QGraphicsScene,QColor,QGraphicsTextItem,QFont
from PyQt4.QtCore import QPointF,QSizeF,QObject,QRectF,QPoint
from PyQt4 import QtCore,QtGui,Qt
from KCharts.KGraphics.KPriceDisplayItem import KPriceDisplayItem
from KCharts.KGraphics.KVolDisplayItem import KVolDisplayItem
from KCharts.KGraphics.KMouseDisplayItem import KMouseDisplayItem
from KCharts.KGraphics.KBaseDisplayItem import KBaseDisplayItem
from KCharts.KGraphics.KGraphicsSceneSubViewModel import KGraphicsSceneSubViewModel 
from KCharts.KGraphics.KGraphicsSceneMenu import KGraphicsSceneMenu
from KApp import KConstants as vm
import collections
from KIndicators import *
import importlib
import imp
class KGraphicsScene(QGraphicsScene):
	ContextMenuClicked=Qt.pyqtSignal(str) # this signal is triggered by context menu and scene will pass it up to singlechartwidget
	def __init__(self,parent,stockobject):
		QGraphicsScene.__init__(self,parent)
		self.m_stock=stockobject
		self.ContextMenuClicked.connect(parent.ContextMenuClicked) # inform parent- singlechartwidget
		self.ViewList=collections.OrderedDict() # maintain all views
	
		
		self.Margin=0 # distance between the scene border and actaul drawing area of the scene	
		self.setBackgroundBrush(QColor(0,0,0)); #black color by default
		
		self.dispitems={} # maitain all display items in the scence
		self.setSceneRect(0,0,100,100) # by default


		# intialize window structure
	def mousePressEvent(self, event):
		if event.button() == QtCore.Qt.RightButton:
			event.accept()
			menu = KGraphicsSceneMenu(self) 
			action = menu.exec_(self.parent().mapToGlobal(event.scenePos().toPoint())) # Translates the widget coordinate pos to global screen coordinate


	def mouseMoveEvent(self,evt):
		pos=evt.lastScenePos()
		for each_item in self.items():
			if issubclass(each_item.__class__,KBaseDisplayItem):
				each_item.OnMouseMove(pos)
	

	def QueryItemByName(self,name):
		# Query an graphics item by name
		for each_item in self.ViewList.values():
			if isinstance(each_item,KGraphicsSceneSubViewModel) and each_item.GetViewName()==name:
					return each_item;
		return None
	

	def AddDisplayItem(self,itemname, iteminstance):
		# add a display item to the scene dynamically
		if itemname not in self.dispitems: # never added or added but removed later
			self.dispitems[itemname]=iteminstance
			self.addItem(iteminstance)
			self.UpdateLogicMapForView(iteminstance.GetViewModel())
			
	def RemoveDisplayItem(self,itemname):
		#
		if itemname in self.dispitems:	
			if self.dispitems[itemname]: # if the object is none, meaning removed already
				iteminstance=self.dispitems[itemname]
				self.removeItem(iteminstance)
				del self.dispitems[itemname]# remove the instance
				self.UpdateLogicMapForView(iteminstance.GetViewModel())	
				
				
	def ComputeAllModels(self):
		# recalculate all model contents of each display item
		for each_item in self.dispitems.values():
			model =each_item.GetModel()
			if model:
				model.calcluate()
			
	
	def GetViewByName(self,name):
		if name in self.ViewList:
			return self.ViewList[name]
		else:
			return None
	
	def GetDispItemsOfView(self,viewname):
		# get all display items belonging to the view
		itemlist=[]
		for each_item in self.dispitems.values():
			viewobj=each_item.GetViewModel()
			if viewobj.GetViewName()==viewname:
				itemlist.append(each_item)
		return itemlist
		
	def CreateInitialViewModels(self):
		

		# Size Policy=0 means the view is cross the whole scene
		
		entireview=KGraphicsSceneSubViewModel(self,{vm.DictType.Name:'GridView',vm.DictType.SizePolicy:0})
		self.AddSubViewModel(entireview)		

		mainview=KGraphicsSceneSubViewModel(self,{vm.DictType.Name:'PriceView',vm.DictType.SizePolicy:3})
		self.AddSubViewModel(mainview)
		
		viceview=KGraphicsSceneSubViewModel(self,{vm.DictType.Name:'VolView',vm.DictType.SizePolicy:1})
		self.AddSubViewModel(viceview)
		
		self.UpdateViewModelHierarchy()
		self.UpdateViewsGeometry()	



	
	def AddSubViewModel(self,model):
		viewname=model.GetViewName()
		self.ViewList[viewname]=model
	
	def UpdateViewModelHierarchy(self):
		# should be call after all views are added, will add partial views into each entire view
		
		entireviews=[]
		patialviews=[]
		for each_view in self.ViewList.values():		
			sizepolicy=each_view.GetSizePolicy()
			if sizepolicy==0: # means it is an entire view
				entireviews.append(each_view)
			else:
				patialviews.append(each_view)
		for parentview in entireviews:
			for childview in patialviews:
				parentview.AddChildModel(childview)

		
	def setSceneRect(self,x,y,w,h):
		
		QGraphicsScene.setSceneRect(self,x,y,w,h)
		self.UpdateViewsGeometry()		# update views geomertry after scene rect is changed
		
	def update(self,rect):
		self.UpdateViewsGeometry()	# update views geomertry before invoke redraw
		QGraphicsScene.update(self,rect)
		
	
	def UpdateViewsGeometry(self):
		''' update the size of all views inside the scene, also the datastruce of mappping logical cordinate to scene cordinates.
		should be called whenever scenerect changed, stock symbol changed, moved, or scaled
		'''
		if len(self.ViewList)==0:
			return False
		# update all view size
		msceneRect=self.sceneRect()		
		totalheightcount=0
		totalactualheight=msceneRect.height()-2*self.Margin
		for each_view in self.ViewList.values():
			totalheightcount+=each_view.GetSizePolicy()
		heigheachcount=totalactualheight*1.0/totalheightcount
		
		# Update each viewmodel
		curheight=self.Margin
		for each_view in self.ViewList.values():
			# update the rect for the view
			m_rect=QRectF()
			if each_view.IsCrossScene()==False: # does this view cross the whole scene
				viewheight=heigheachcount*each_view.GetSizePolicy()
				m_viewpoint=QPointF(msceneRect.left()+self.Margin,curheight)
				m_viewsize=QSizeF(msceneRect.width()-2*self.Margin,viewheight)
				m_rect=QRectF(m_viewpoint,m_viewsize)
				# update mapping data structure
				curheight+=viewheight
			else:
				m_viewpoint=QPointF(msceneRect.left()+self.Margin,msceneRect.top()+self.Margin)
				m_viewsize=QSizeF(msceneRect.width()-2*self.Margin,msceneRect.height()-2*self.Margin)
				m_rect=QRectF(m_viewpoint,m_viewsize)
				
			each_view.SetViewRect(m_rect)	
			# update logic map for the view
			self.UpdateLogicMapForView(each_view)
	
			#print("Updating View Geometry:%s, New Rect: %s" %(each_view.GetViewName(),m_rect))
			
		# Update each items's prerender picture based on new viewmodel
		for each_item in self.items():
			if issubclass(each_item.__class__,KBaseDisplayItem):
				each_item.PrepareRenderPicture()
		return True
	
	def UpdateLogicMapForView(self,viewinstance):
		# update logic map for the view
		dispitems=self.GetDispItemsOfView(viewinstance.GetViewName())
		if dispitems:
			viewinstance.UpdateLogicMap(self.m_stock,dispitems) 			
		  

		
		
		